#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys
import subprocess
import os
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLabel, QLineEdit, QPushButton, QListWidget, QTextEdit, 
                             QMessageBox, QGroupBox, QInputDialog, QProgressDialog)
from PyQt5.QtCore import Qt, QThread, pyqtSignal

class UninstallWorker(QThread):
    """
    在后台线程中执行卸载操作，避免界面冻结
    """
    progress = pyqtSignal(str)
    finished = pyqtSignal(bool, str)
    
    def __init__(self, package_name, password):
        super().__init__()
        self.package_name = package_name
        self.password = password
    
    def run(self):
        try:
            self.progress.emit("正在卸载软件包...")
            
            result = subprocess.run(['sudo', '-S', 'apt', 'remove', '-y', self.package_name], 
                                  input=self.password + '\n', capture_output=True, text=True)
            
            if result.returncode != 0:
                if "password" in result.stderr.lower() or "密码" in result.stderr.lower():
                    self.finished.emit(False, "密码错误，请重试")
                    return
                else:
                    self.finished.emit(False, f"卸载失败: {result.stderr}")
                    return
            
            self.progress.emit("正在清理残留文件...")
            result = subprocess.run(['sudo', '-S', 'apt', 'purge', '-y', self.package_name], 
                                  input=self.password + '\n', capture_output=True, text=True)
            
            if result.returncode != 0:
                self.finished.emit(False, f"清理失败: {result.stderr}")
                return
                
            self.progress.emit("正在自动移除不需要的包...")
            result = subprocess.run(['sudo', '-S', 'apt', 'autoremove', '-y'], 
                                  input=self.password + '\n', capture_output=True, text=True)
            
            if result.returncode != 0:
                self.finished.emit(False, f"自动移除失败: {result.stderr}")
                return
                
            self.progress.emit("正在清理缓存...")
            result = subprocess.run(['sudo', '-S', 'apt', 'autoclean'], 
                                  input=self.password + '\n', capture_output=True, text=True)
            
            if result.returncode != 0:
                self.finished.emit(False, f"清理缓存失败: {result.stderr}")
                return
                
            self.progress.emit("操作完成")
            self.finished.emit(True, f"{self.package_name} 卸载完成!")
            
        except Exception as e:
            self.finished.emit(False, f"发生错误: {str(e)}")


class XYSoftUninstaller(QMainWindow):
    def __init__(self):
        super().__init__()
        self.matches = []
        self.filtered_matches = []  # 添加这一行来存储过滤后的结果
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle('咸鱼软件卸载工具 By:xianyuwangyou')
        self.setGeometry(100, 100, 800, 600)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        
        # 搜索区域
        search_group = QGroupBox("搜索软件")
        search_layout = QHBoxLayout(search_group)
        
        self.search_input = QLineEdit()
        self.search_input.setPlaceholderText("请输入软件的名称/功能/描述关键词")
        self.search_input.textChanged.connect(self.on_search_text_changed)
        self.search_button = QPushButton("搜索")
        self.search_button.clicked.connect(self.search_packages)
        self.clear_search_button = QPushButton("清空")
        self.clear_search_button.clicked.connect(self.clear_search)
        
        search_layout.addWidget(QLabel("关键词:"))
        search_layout.addWidget(self.search_input)
        search_layout.addWidget(self.search_button)
        search_layout.addWidget(self.clear_search_button)
        
        # 结果显示区域
        result_group = QGroupBox("已安装软件列表")
        result_layout = QVBoxLayout(result_group)
        
        self.result_list = QListWidget()
        self.result_list.itemClicked.connect(self.on_item_clicked)
        self.result_list.itemDoubleClicked.connect(self.uninstall_package)
        result_layout.addWidget(self.result_list)
        
        # 按钮区域
        button_layout = QHBoxLayout()
        self.uninstall_button = QPushButton("卸载选中软件")
        self.uninstall_button.clicked.connect(self.uninstall_package)
        self.uninstall_button.setEnabled(False)
        
        self.refresh_button = QPushButton("刷新列表")
        self.refresh_button.clicked.connect(self.load_all_packages)
        
        self.exit_button = QPushButton("退出")
        self.exit_button.clicked.connect(self.close)
        
        button_layout.addWidget(self.uninstall_button)
        button_layout.addWidget(self.refresh_button)
        button_layout.addStretch()
        button_layout.addWidget(self.exit_button)
        
        # 添加所有组件到主布局
        main_layout.addWidget(search_group)
        main_layout.addWidget(result_group)
        main_layout.addLayout(button_layout)
        
        self.search_input.returnPressed.connect(self.search_packages)
        
        # 程序启动时加载所有已安装的软件列表
        self.load_all_packages()
    
    def load_all_packages(self):
        """加载所有已安装的软件包"""
        try:
            # 显示加载提示
            self.result_list.clear()
            self.result_list.addItem("正在加载软件列表...")
            QApplication.processEvents()  # 确保界面更新
            
            # 获取所有已安装的软件包
            result = subprocess.run(['dpkg', '-l'], capture_output=True, text=True)
            
            if result.returncode == 0:
                lines = result.stdout.split('\n')
                self.matches = []
                
                # 收集所有软件包名称
                package_names = []
                temp_matches = []
                
                for line in lines:
                    if line.startswith('ii'):
                        parts = line.split()
                        if len(parts) >= 3:
                            package_name = parts[1]
                            package_desc = ' '.join(parts[3:]) if len(parts) > 3 else ''
                            package_names.append(package_name)
                            temp_matches.append((package_name, package_desc))
                
                # 批量获取本地化描述
                localized_descriptions = self.get_localized_descriptions(package_names)
                
                # 合并信息
                for package_name, default_desc in temp_matches:
                    localized_desc = localized_descriptions.get(package_name, "")
                    final_desc = localized_desc if localized_desc else default_desc
                    self.matches.append((package_name, final_desc))
                
                # 显示所有软件包
                self.display_packages(self.matches)
                
                if not self.matches:
                    QMessageBox.information(self, "提示", "未找到已安装的软件包")
            else:
                self.result_list.clear()
                self.result_list.addItem("加载软件列表失败")
                QMessageBox.critical(self, "错误", "执行dpkg命令出错")
        except Exception as e:
            self.result_list.clear()
            self.result_list.addItem("加载软件列表时发生错误")
            QMessageBox.critical(self, "错误", f"加载软件列表时发生错误: {str(e)}")
    
    def get_localized_descriptions(self, package_names):
        """批量获取软件包的本地化描述"""
        descriptions = {}
        try:
            # 使用apt show命令批量获取软件包信息
            result = subprocess.run(['apt', 'show'] + package_names, 
                                  capture_output=True, text=True, timeout=30)
            
            if result.returncode == 0:
                # 解析输出获取描述信息
                blocks = result.stdout.split('\n\n')
                for block in blocks:
                    lines = block.split('\n')
                    package_name = ""
                    
                    # 查找包名
                    for line in lines:
                        if line.startswith("Package:"):
                            package_name = line[9:].strip()  # "Package:" 后面的内容
                            break
                    
                    if package_name:
                        # 查找本地化描述
                        description_prefix = "Description:"
                        long_description_prefix = "Description-zh-cn:"
                        
                        # 优先查找中文描述
                        for line in lines:
                            if line.startswith(long_description_prefix):
                                descriptions[package_name] = line[len(long_description_prefix):].strip()
                                break
                        
                        # 如果没有中文描述，查找默认描述
                        if package_name not in descriptions:
                            for line in lines:
                                if line.startswith(description_prefix):
                                    descriptions[package_name] = line[len(description_prefix):].strip()
                                    break
            
            return descriptions
        except Exception:
            return descriptions  # 发生异常时返回已获取的描述
    
    def display_packages(self, packages):
        """显示软件包列表"""
        self.result_list.clear()
        
        if not packages:
            self.result_list.addItem("未找到匹配的已安装软件！")
            self.uninstall_button.setEnabled(False)
            return
        
        for i, (name, desc) in enumerate(packages):
            item_text = f"{i+1}. {name}"
            if desc:
                item_text += f"\n   描述: {desc[:100]}{'...' if len(desc) > 100 else ''}"
            self.result_list.addItem(item_text)
        
        self.uninstall_button.setEnabled(False)  # 默认不选中任何项
    
    def on_search_text_changed(self, text):
        """处理搜索框文本变化事件，实现实时搜索"""
        if not text:
            self.filtered_matches = self.matches
            self.display_packages(self.matches)
            return
        
        matched_packages = []
        for name, desc in self.matches:
            if text.lower() in name.lower() or text.lower() in desc.lower():
                matched_packages.append((name, desc))
        
        self.filtered_matches = matched_packages
        self.display_packages(matched_packages)
    
    def search_packages(self):
        """根据关键词搜索软件包（点击搜索按钮时调用）"""
        keyword = self.search_input.text().strip()
        
        if not keyword:
            self.filtered_matches = self.matches
            self.display_packages(self.matches)
            return
            
        matched_packages = []
        for name, desc in self.matches:
            if keyword.lower() in name.lower() or keyword.lower() in desc.lower():
                matched_packages.append((name, desc))
        
        self.filtered_matches = matched_packages
        self.display_packages(matched_packages)
        
        if not matched_packages:
            QMessageBox.information(self, "提示", "未找到匹配的已安装软件！")
    
    def on_item_clicked(self, item):
        """处理列表项点击事件"""
        self.uninstall_button.setEnabled(True)
    
    def uninstall_package(self):
        # 修改这里，使用filtered_matches而不是matches
        current_row = self.result_list.currentRow()
        if current_row < 0 or current_row >= len(self.filtered_matches):
            QMessageBox.warning(self, "警告", "请先选择要卸载的软件")
            return
            
        # 从filtered_matches获取要卸载的软件包
        package_name, package_desc = self.filtered_matches[current_row]
        
        reply = QMessageBox.question(self, "确认", 
                                   f"确定要卸载「{package_name}」并清理残留吗？",
                                   QMessageBox.Yes | QMessageBox.No,
                                   QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            self.start_uninstall(package_name)
    
    def start_uninstall(self, package_name):
        password, ok = QInputDialog.getText(self, "权限验证", 
                                          "请输入您的sudo密码:", QLineEdit.Password)
        if not ok or not password:
            self.uninstall_button.setEnabled(True)
            self.search_button.setEnabled(True)
            return
            
        self.uninstall_button.setEnabled(False)
        self.search_button.setEnabled(False)
        
        # 创建进度对话框
        self.progress_dialog = QProgressDialog("开始卸载...", "取消", 0, 4, self)
        self.progress_dialog.setWindowTitle("卸载进度")
        self.progress_dialog.setModal(True)
        self.progress_dialog.setAutoClose(False)
        self.progress_dialog.setAutoReset(False)
        self.progress_dialog.show()
        
        self.worker = UninstallWorker(package_name, password)
        self.worker.progress.connect(self.update_progress)
        self.worker.finished.connect(self.uninstall_finished)
        self.worker.start()
    
    def update_progress(self, message):
        """更新进度对话框"""
        current_value = self.progress_dialog.value()
        self.progress_dialog.setValue(current_value + 1)
        self.progress_dialog.setLabelText(message)
    
    def uninstall_finished(self, success, message):
        """卸载完成处理"""
        if hasattr(self, 'progress_dialog'):
            self.progress_dialog.close()
            
        self.uninstall_button.setEnabled(True)
        self.search_button.setEnabled(True)
        
        if success:
            QMessageBox.information(self, "成功", message)
            current_row = self.result_list.currentRow()
            self.result_list.takeItem(current_row)
            if current_row < len(self.filtered_matches):
                del self.filtered_matches[current_row]
                # 同时也需要从原始matches列表中删除
                index_to_remove = None
                for i, (name, desc) in enumerate(self.matches):
                    if name == self.filtered_matches[min(current_row, len(self.filtered_matches)-1)][0] if self.filtered_matches else None:
                        index_to_remove = i
                        break
                if index_to_remove is not None:
                    del self.matches[index_to_remove]
        else:
            QMessageBox.critical(self, "错误", message)
    
    def clear_search(self):
        """清空搜索框并显示所有软件包"""
        self.search_input.clear()


def main():
    app = QApplication(sys.argv)
    
    app.setApplicationName("XY软件卸载工具")
    app.setApplicationVersion("1.0")
    
    window = XYSoftUninstaller()
    window.show()
    
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()